#include "include.h"

#define MAX_HTTP_RECV_BUFFER 512
#define MAX_HTTP_OUTPUT_BUFFER 2048
#define EXAMPLE_ESP_MAXIMUM_RETRY 5

httpd_handle_t websvr;

typedef enum
{
    STATE_NO_WIFI_INFO = 0, /**< 没有WIFI信息 */
    STATE_ON_START,         /**< 没有WIFI信息 */
    STATE_MAX
} app_http_state_t;

static const char *TAG = "app_http_request";
extern EventGroupHandle_t app_event_handle;
static int s_retry_num = 0;
uint8_t net_state = NET_STATE_GETTO_NULL; /*<! 标识当前网络状态 */

esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    static char *output_buffer; // Buffer to store response of http request from event handler
    static int output_len;      // Stores number of bytes read
    switch (evt->event_id)
    {
    case HTTP_EVENT_ERROR:
        ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
        break;
    case HTTP_EVENT_HEADER_SENT:
        ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
        break;
    case HTTP_EVENT_ON_HEADER:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
        break;
    case HTTP_EVENT_ON_DATA:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
        /*
             *  Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
             *  However, event handler can also be used in case chunked encoding is used.
             */
        if (!esp_http_client_is_chunked_response(evt->client))
        {
            // If user_data buffer is configured, copy the response into the buffer
            if (evt->user_data)
            {
                memcpy(evt->user_data + output_len, evt->data, evt->data_len);
            }
            else
            {
                if (output_buffer == NULL)
                {
                    output_buffer = (char *)malloc(esp_http_client_get_content_length(evt->client));
                    output_len = 0;
                    if (output_buffer == NULL)
                    {
                        ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
                        return ESP_FAIL;
                    }
                }
                memcpy(output_buffer + output_len, evt->data, evt->data_len);
            }
            output_len += evt->data_len;
        }

        break;
    case HTTP_EVENT_ON_FINISH:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
        if (output_buffer != NULL)
        {
            // Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
            // ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
            free(output_buffer);
            output_buffer = NULL;
            output_len = 0;
        }
        break;
    case HTTP_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
        int mbedtls_err = 0;
        esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
        /*
            不知道为什么注释这两个地方就不会pos多了就复位了
        */
        if (err != 0)
        {
            if (output_buffer != NULL)
            {
                free(output_buffer);
                output_buffer = NULL;
                output_len = 0;
            }
            ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
            ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
        }
        break;
    }
    return ESP_OK;
}

esp_err_t http_rest_image_jpeg(uint8_t *jpeg_data, size_t len)
{
    char url[URL_LENGTH_MAX] = {0};
    if (get_app_url(DEMOKS_CEYE_HTTP_PHOTO_URL, &url) != ESP_OK)
    {
        ESP_LOGW(TAG, "没有设置图片传输的URL");
        return ESP_FAIL;
    }

    ESP_LOGI(TAG, "[free mem good=%d;] \n", esp_get_free_heap_size());
    ESP_LOGI(TAG, "读取URL:%s", url);

    // 等待入网
    EventBits_t bits = xEventGroupWaitBits(app_event_handle,
                                           APP_EVENT_BIT_WIFI_CONNECTED,
                                           pdFALSE,
                                           pdFALSE,
                                           (portTickType)3000 / portTICK_RATE_MS);
    if (!(bits & APP_EVENT_BIT_WIFI_CONNECTED))
    {
        ESP_LOGW(TAG, "设备未入网");
        return ESP_FAIL;
    }
    
    char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};

    esp_http_client_config_t config = {
        .url = &url,
        .event_handler = _http_event_handler,
        .user_data = local_response_buffer,
    };
    esp_http_client_handle_t client = esp_http_client_init(&config);
    
    esp_http_client_delete_header(client, "User-Agent");
    // POST
    esp_http_client_set_url(client, &url);
    esp_http_client_set_method(client, HTTP_METHOD_POST);
    esp_http_client_set_header(client, "Content-Type", "application/octet-stream");
    esp_http_client_set_post_field(client, (const char *)jpeg_data, len);
    esp_err_t err = esp_http_client_perform(client);

    if (err == ESP_OK)
        ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %d",
                 esp_http_client_get_status_code(client),
                 esp_http_client_get_content_length(client));
    else
        ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
    esp_http_client_cleanup(client);
    return err;
}

static void event_handler(void *arg, esp_event_base_t event_base,
                          int32_t event_id, void *event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
    {
        esp_wifi_connect();
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
        net_state = NET_STATE_GETTO_NULL; /*<! 无网络状态 */
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY)
        {
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        }
        else
        {
            xEventGroupSetBits(app_event_handle, APP_EVENT_BIT_WIFI_FAIL);
        }
        ESP_LOGI(TAG, "connect to the AP fail");
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(app_event_handle, APP_EVENT_BIT_WIFI_CONNECTED);
        uint8_t primary;
        wifi_second_chan_t second;
        esp_wifi_get_channel(&primary, &second);
        set_wifi_info(NULL, NULL, NULL, &primary); /*>! 保存当前信道信息,有助下次连接该WIFI不用重新收拾信道 */
        net_state = NET_STATE_GETTO_ROUTE;         /*<! 已接入路由 */
    }

    if (event_id == WIFI_EVENT_AP_STACONNECTED) {
        wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
                 MAC2STR(event->mac), event->aid);
    } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
        wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
                 MAC2STR(event->mac), event->aid);
    }
}

void wifi_init_sta(void *pvParameters)
{
    esp_netif_create_default_wifi_sta();
    esp_netif_create_default_wifi_ap();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config_sta = {
        .sta = {
            .ssid = {0},
            .password = {0},
            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
            .pmf_cfg = {
                .capable = true,
                .required = false},
            .channel = 0,
        },
    };
    
    char ap_name[32];
    memset(ap_name,0,sizeof(ap_name));
    sprintf(ap_name,"lononCam_%s",get_esp32_mac_address());
    
    wifi_config_t wifi_config_ap = {
        .ap = {
            .ssid_len = strlen(ap_name),
            .channel = 1,
            .password = "12345678",
            .max_connection = 1,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK
        },
    };

    strncpy((char *)wifi_config_ap.ap.ssid,ap_name,strlen(ap_name));

    printf("ap name = %s\n", ap_name);
    
    uint8_t state = STATE_NO_WIFI_INFO;

    while (true)
    {
        esp_err_t result = get_wifi_info(
            &wifi_config_sta.sta.ssid,
            &wifi_config_sta.sta.password,
            &wifi_config_sta.sta.threshold.authmode,
            &wifi_config_sta.sta.channel);

        ESP_LOGI(TAG, "ss_ssid=%.*s;", 32, wifi_config_sta.sta.ssid);
        ESP_LOGI(TAG, "ss_password=%.*s;", 64, wifi_config_sta.sta.password);
        ESP_LOGI(TAG, "ss_authmode=%x;", wifi_config_sta.sta.threshold.authmode);
        ESP_LOGI(TAG, "ss_channel=%x;", wifi_config_sta.sta.channel);
        /**
         * 判断获取的wifi信息是否正常
         * 正常就跳出循环进行连接
         */
        if (result == ESP_OK)
        {
            switch (state)
            {
            case STATE_NO_WIFI_INFO:
            {
                ESP_LOGI(TAG, "首次入网");
                ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
                ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config_sta));
                ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config_ap));
                ESP_ERROR_CHECK(esp_wifi_start());

                websvr = start_webserver();
                state = STATE_ON_START;
                break;
            }
            case STATE_ON_START:
            {
                s_retry_num = 0;
                ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config_sta));
                if (net_state == NET_STATE_GETTO_NULL)
                    esp_wifi_connect();
                else if (net_state == NET_STATE_GETTO_ROUTE)
                    esp_wifi_disconnect();
                break;
            }
            default:
                break;
            }
        }
        else
        {
            /*
                开启热点
            */
            ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
            ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config_ap));
            ESP_ERROR_CHECK(esp_wifi_start());

            start_webserver();
        }
        
        /*>! 等待接收新的WIFI信息 */
        ESP_LOGI(TAG, "等待接收新的WIFI信息");
        xEventGroupWaitBits(app_event_handle,
                            APP_EVENT_BIT_ON_SET_WIFI_INFO,
                            pdTRUE,
                            pdFALSE,
                            (portTickType)portMAX_DELAY);
        ESP_LOGI(TAG, "收到WIFI信息");
    }

    vTaskDelete(NULL);
}
